import json
import xml.etree.ElementTree
from os.path import join

import sumolib
import traci

import rou
import scene
import rou.constants as rc
from rou._route_detail import RouteDetail
import sumo_utils
import random
import uuid


class ConfigItem:
    rou_type_map = {
        'hello.rou1.xml': 0,
        'hello.rou.xml': 1
    }

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls)

    def __init__(self, no, name: str, cfg_path: str, r_type=None, route=None):
        self.no = no
        self.name = name if len(name.strip()) > 0 else '路由方案' + str(no)
        self.type = r_type
        self.route = route
        self.scene_info = scene.SceneConfig()

        rou_name, net_name = self.get_base_from_cfg_path(cfg_path)
        self.rou_name = rou_name
        self.net_name = rou_name
        if r_type is None:
            self.r_type = self.rou_type_map[rou_name] if rou_name in self.rou_type_map.keys() else 3
        self.rou_path = join(rc.DEFAULT_PATH, rou_name)
        self.net_path = join(rc.DEFAULT_PATH, net_name)

        if route is None:
            self.route = self.get_route(self.rou_path, self.net_path)
        else:
            self.name = '路由方案2_自由路由'
            self.r_type = 1
            self.type = r_type
            self.route = self.getFreeRoute(self.net_path, routeid=route,vehiclePoints=[],result=[])

    def get_base_from_cfg_path(self, cfg_path: str):
        tree = xml.etree.ElementTree.parse(cfg_path)
        root = tree.getroot()
        input_label = root.find('input')
        # 路网文件
        net_file_label = input_label.find('net-file')
        net_name = net_file_label.attrib['value']
        # 路由文件
        rou_file_label = input_label.find('route-files')
        rou_name = rou_file_label.attrib['value']
        return rou_name, net_name

    def get_route(self, rou_file: str, sumo_net_file: str):
        tree = xml.etree.ElementTree.parse(rou_file)
        root = tree.getroot()
        route_labels = root.findall('route')
        result = list()
        for r_label in route_labels:
            route_id = r_label.attrib['id']
            route = str(r_label.attrib['edges']).split(' ')
            sumo_net_instance = sumolib.net.readNet(sumo_net_file, withInternal=True, withLatestPrograms=True)
            routes = list()
            for edge_id in route:
                if len(str(edge_id).strip()) == 0:
                    continue
                edge = sumo_net_instance.getEdge(edge_id)
                shape = edge.getRawShape3D()
                point = sumo_net_instance.convertXY2LonLat(shape[0][0], shape[0][1])
                routes.append(point)
            if len(routes) > 0:
                result.append(RouteDetail(route_id, routes).to_dict())
        return result
    def get_routePoint( rou_file: str, sumo_net_file: str):
        tree = xml.etree.ElementTree.parse(rou_file)
        root = tree.getroot()
        route_labels = root.findall('route')
        result = list()
        for r_label in route_labels:
            route_id = r_label.attrib['id']
            route = str(r_label.attrib['edges']).split(' ')
            sumo_net_instance = sumolib.net.readNet(sumo_net_file, withInternal=True, withLatestPrograms=True)
            routes = list()
            # for edge_id in route:
            #     if len(str(edge_id).strip()) == 0:
            #         continue
            #     edge = sumo_net_instance.getEdge(edge_id)
            #     shape = edge.getRawShape3D()
            #     point = sumo_net_instance.convertXY2LonLat(shape[0][0], shape[0][1])
            #     routes.append(point)
            for edge_id in route:
                if len(str(edge_id).strip()) == 0:
                    continue
                edge = sumo_net_instance.getEdge(edge_id)
                # if edge_id == '-301.0.00' or edge_id == '-302.0.00' or edge_id == '-276.0.00' or edge_id == '-266.0.00' or edge_id == '-268.0.00' or edge_id == '-260.0.00' or edge_id == '-264.0.00' or edge_id == '-560.0.00' or edge_id == '-549.0.00':
                if edge_id is not None:
                    shape = edge.getRawShape3D()
                    for sh in shape:
                        point = sumo_net_instance.convertXY2LonLat(sh[0], sh[1])
                        routes.append(point)
                else:
                    shape = edge.getRawShape3D()
                    start_coord = shape[0]  # x, y, z of the start of the edge
                    center_coord = shape[len(shape) // 2]  # x, y, z of the center of the edge
                    end_coord = shape[-1]  # x, y, z of the end of the edge
                    # point = sumo_net.convertXY2LonLat(shape[0][0], shape[0][1])
                    start_coord_point = sumo_net_instance.convertXY2LonLat(start_coord[0], start_coord[1])
                    center_coord_point = sumo_net_instance.convertXY2LonLat(center_coord[0], center_coord[1])
                    end_coord_point = sumo_net_instance.convertXY2LonLat(end_coord[0], end_coord[1])
                    routes.append(start_coord_point)
                    routes.append(center_coord_point)
                    routes.append(end_coord_point)
            if len(routes) > 0:
                result.append(RouteDetail(route_id, routes).to_dict())
        return result
    def getFreeRoute(self, sumo_net_file: str, routeid: str,vehiclePoints: list,result: list):
        if len(vehiclePoints)==0:
        # vehicleNum=50
            vehiclePoints = '[]'
            # vehiclePoints='[{"lat":34.372449,"lon":108.892912},{"lat":34.375380,"lon":108.899382}]'
            result = [{"arrive": [],
                      "depart": {"autonomousRatio": 0, "busRatio": 0, "count": 0, "point": [], "simplePassengerRatio": 0},
                      "id": "",
                      "route": [],
                      "type": 1}
                      ]
        sumo_net = sumolib.net.readNet(sumo_net_file, withInternal=True, withLatestPrograms=True)
        vehiclePointsobj = json.loads(vehiclePoints)
        for vehiclePoint in vehiclePointsobj:
            lat = float(vehiclePoint["lat"])
            lon = float(vehiclePoint["lon"])
            x, y = sumo_net.convertLonLat2XY(lon, lat)
            sumo_cfg_file = "../webgl/长安大学_openDrive_v0.sumocfg"
            # sumo_utils.start_sumo(sumo_cfg_file, False, gui=False)
            # x,y=sumo_utils.latAndLonConversionXY(sumo_net,(lon, lat))
            startedgeID, startpos, startlaneIndex = traci.simulation.convertRoad(lon, lat, True)
            traci.close()
            # startedgeID='-291.0.00'
            single_edge = sumo_net.getEdge(startedgeID)
            if single_edge is not None:
                route = [startedgeID]
                count = 0
                while single_edge is not None:
                    edge_Bound = single_edge.getOutgoing()
                    edgeids = list()
                    for k, v in edge_Bound.items():
                        edgeids.append(k.getID())
                    if edgeids is not None and len(edgeids) > 0:
                        try:
                            id = random.choice(edgeids)
                            if True:
                                route.append(id)
                            else:
                                logging.info("Road marking problem1")
                                errorMsg = "标注错误，请重新标注"
                            single_edge = sumo_net.getEdge(id)
                        except ValueError:
                            continue
                        # break
                    count += 1
                    if len(route) > 1000 or count > 200 or '-547.0.00' in route:
                        print(route)
                        break
                # routeid = str(uuid.uuid1())
                routes = list()
                for edge_id in route:
                    if len(str(edge_id).strip()) == 0:
                        continue
                    edge = sumo_net.getEdge(edge_id)
                    shape = edge.getRawShape3D()
                    point = sumo_net.convertXY2LonLat(shape[0][0], shape[0][1])
                    routes.append(point)
                    # if len(routes) > 0:
                    if len(vehiclePoints) == 0 and len(result) == 0:
                        result.append(
                            RouteDetail(routeid, routes, v_count=0, a_type=2, simple_passenger_ratio=0.0, bus_ratio=0.0,
                                        autonomous_ratio=0.0).to_dict())
                    else:
                        result.append(RouteDetail(routeid, routes, v_count=0, a_type=2, simple_passenger_ratio=0.0, bus_ratio=0.0,
                                        autonomous_ratio=0.0).to_dict())

                # traci.route.add(routeid, route)




            else:
                logging.info("Road marking problem1")
                errorMsg = "标注错误，请重新标注"
        return result

    def to_dict(self):
        return {
            'no': self.no,
            'name': self.name,
            'rouName': self.rou_name,
            'type': self.r_type,
            'route': self.route,
            'netPath': self.net_path,
            'rouPath': self.rou_path,
            'sceneInfo': self.scene_info.to_dict()
        }
